package org.feng.client;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ReactiveRedisTemplate;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.Objects;

/**
 * 自定义业务客户端
 *
 * @version v1.0
 * @author: fengjinsong
 * @date: 2022年11月06日 11时22分
 */
@Slf4j
@Component
public class CustomRedisClient {
    private CustomRedisBean customRedisBean;
    private ReactiveRedisTemplate<String, Object> reactiveRedisTemplate;
    private CustomRedisProperties customRedisProperties;

    @Autowired
    private CustomRedisClient(ReactiveRedisTemplate<String, Object> reactiveRedisTemplate, CustomRedisProperties customRedisProperties) {
        this.init(reactiveRedisTemplate, customRedisProperties);
    }

    private void init(ReactiveRedisTemplate<String, Object> reactiveRedisTemplate, CustomRedisProperties customRedisProperties) {
        log.info("初始化自定义Redis客户端");
        this.reactiveRedisTemplate = reactiveRedisTemplate;
        this.customRedisProperties = customRedisProperties;
    }

    public void setBusiness(String businessKey) {
        this.customRedisBean = customRedisProperties.getCustomRedisBeanByKey(businessKey);
        // 数据校验失败：配置信息不完整
        if (Objects.isNull(customRedisBean) || !customRedisBean.validate()) {
            throw new IllegalArgumentException("信息不完整，请检查配置");
        }
    }

    /**
     * 设置存储键、值
     *
     * @param key   键
     * @param value 值
     */
    public void setValue(String key, Object value) {
        String realBusinessKey = generateBusinessKey(key);
        // 存储key-value数据
        reactiveRedisTemplate.opsForValue().set(realBusinessKey, value).subscribe();
    }

    /**
     * 通过键获取值
     *
     * @param key 键
     */
    public Mono<Object> get(String key) {
        String realBusinessKey = generateBusinessKey(key);
        return reactiveRedisTemplate.opsForValue().get(realBusinessKey);
    }

    public void setValueWithTimeOut(String key, String value) {
        String realBusinessKey = customRedisBean.getBusinessPrefix() + key;
        ChronoUnit expireTimeUnit = customRedisBean.getExpireTimeUnit();
        Duration timeout = Duration.of(customRedisBean.getBusinessExpireTime(), expireTimeUnit);
        reactiveRedisTemplate.opsForValue().set(realBusinessKey, value, timeout).subscribe();
    }


    /**
     * 如果不存在当前的键，则将键值存储，并返回true；若存在当前键，则不做操作，返回false
     *
     * @param key   键
     * @param value 值
     * @return 当前键不存在，存储当前键值，返回true
     */
    public Mono<Boolean> setIfAbsent(String key, Object value) {
        String realBusinessKey = customRedisBean.getBusinessPrefix() + key;
        return reactiveRedisTemplate.opsForValue().setIfAbsent(realBusinessKey, value);
    }

    /**
     * 如果不存在当前的键，则将键值存储，并返回true；若存在当前键，则不做操作，返回false<br>
     * 并且设置失效时间
     *
     * @param key   键
     * @param value 值
     * @return 当前键不存在，存储当前键值，返回true
     */
    public Mono<Boolean> setIfAbsentWithTimeOut(String key, Object value) {
        String realBusinessKey = customRedisBean.getBusinessPrefix() + key;
        ChronoUnit expireTimeUnit = customRedisBean.getExpireTimeUnit();
        Duration timeout = Duration.of(customRedisBean.getBusinessExpireTime(), expireTimeUnit);
        return reactiveRedisTemplate.opsForValue().setIfAbsent(realBusinessKey, value, timeout);
    }

    /**
     * 查询是否存在键
     *
     * @param key 键
     * @return 存在时返回true；否则为false
     */
    public Mono<Boolean> hasKey(String key) {
        return reactiveRedisTemplate.hasKey(generateBusinessKey(key));
    }

    public String generateBusinessKey(String key) {
        return customRedisBean.getBusinessPrefix() + key;
    }
}
